package com.itheima.health.config;

import com.itheima.health.common.EncodingIdConst;
import com.itheima.health.exception.BusinessException;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.Map;

/**
 * @Project_Name: itcast_health
 * @package_name: com.itheima.health.config
 * @Author: Boyang
 * @Date: 2021/3/13 10:11
 */
public class MyPassEncoder implements PasswordEncoder {
    private final String idForEncode;
    private final PasswordEncoder passwordEncoderForEncode;
    private final Map<String, PasswordEncoder> idToPasswordEncoder;

    public MyPassEncoder(String idForEncode, Map<String, PasswordEncoder> idToPasswordEncoder) {
        if (idForEncode == null) {
            throw new BusinessException("验证错误请联系管理员");
        }
        if (!idToPasswordEncoder.containsKey(idForEncode)) {
            throw new BusinessException("验证错误请联系管理员");
        }
        this.idForEncode = idForEncode;
        this.idToPasswordEncoder = idToPasswordEncoder;
        this.passwordEncoderForEncode = this.idToPasswordEncoder.get(idForEncode);
    }

    /**
     * @Author: boyang
     * @Date: 11:02 2021/3/13
     * @Param: [rawPassword]
     * @ReturnType: java.lang.String
     * @Description: 对明文密码进行加密,
     */
    @Override
    public String encode(CharSequence rawPassword) {
        if (EncodingIdConst.MD5.equals(idForEncode)) {
            return EncodingIdConst.MD5_PRE + passwordEncoderForEncode.encode(rawPassword);
        } else if (EncodingIdConst.BCRYPT.equals(idForEncode)) {
            return EncodingIdConst.BCRYPT_PRE + passwordEncoderForEncode.encode(rawPassword);
        } else if (EncodingIdConst.MD5_NO_PRE.equals(idForEncode)) {
            return passwordEncoderForEncode.encode(rawPassword);
        } else if (EncodingIdConst.BCRYPT_NO_PRE.equals(idForEncode)) {
            return passwordEncoderForEncode.encode(rawPassword);
        } else {
            //如果未指定加密方式 则默认明文密码
            return rawPassword.toString();
        }

    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        if (null == encodedPassword) {
            return false;
        }
        String password = this.extractPassword(encodedPassword);
        String passwordPre = this.extractId(encodedPassword);
        Boolean flag = false;
        if (encodedPassword == null) {
            return false;
        }
        if (passwordPre == null) {
            boolean md5matches = idToPasswordEncoder.get(EncodingIdConst.MD5_NO_PRE).matches(rawPassword, password);
            boolean bcrypt = idToPasswordEncoder.get(EncodingIdConst.BCRYPT_NO_PRE).matches(rawPassword, password);
            return md5matches || bcrypt;
        }
        if (passwordPre.equals(EncodingIdConst.BCRYPT_PRE)) {
            flag = idToPasswordEncoder.get(EncodingIdConst.BCRYPT).matches(rawPassword, password);
        } else if (passwordPre.equals(EncodingIdConst.MD5_PRE)) {
            flag = idToPasswordEncoder.get(EncodingIdConst.MD5).matches(rawPassword, password);
        }
        return flag;
    }

    /**
     * @Author: boyang
     * @Date: 13:10 2021/3/13
     * @Param: [prefixEncodedPassword]
     * @ReturnType: java.lang.String
     * @Description: 提取加密方式
     */
    public String extractId(String prefixEncodedPassword) {
        int md5End = prefixEncodedPassword.indexOf('_');
        String md5pre = prefixEncodedPassword.substring(0, md5End + 1);
        if (EncodingIdConst.MD5_PRE.equals(md5pre)) {
            return EncodingIdConst.MD5_PRE;
        }
        int bcryptStart = prefixEncodedPassword.indexOf("{");
        int bcryptEnd = prefixEncodedPassword.indexOf("}");
        String bcryptPre = null;
        if (!(bcryptEnd - bcryptStart > 8 || bcryptEnd == -1 || bcryptStart == -1)) {
            bcryptPre = prefixEncodedPassword.substring(bcryptStart, bcryptEnd + 1);
        }
        if (EncodingIdConst.BCRYPT_PRE.equals(bcryptPre)) {
            return EncodingIdConst.BCRYPT_PRE;
        }

        return null;
    }

    /**
     * @Author: boyang
     * @Date: 13:10 2021/3/13
     * @Param: [prefixEncodedPassword]
     * @ReturnType: java.lang.String
     * @Description: 提取加密后的密文
     */
    public String extractPassword(String prefixEncodedPassword) {
        int md5End = prefixEncodedPassword.indexOf('_');
        String md5pre = prefixEncodedPassword.substring(0, md5End + 1);
        int bcryptStart = prefixEncodedPassword.indexOf("{");
        int bcryptEnd = prefixEncodedPassword.indexOf("}");
        String bcryptPre = null;
        if (!(bcryptEnd - bcryptStart > 8 || bcryptEnd == -1 || bcryptStart == -1)) {
            bcryptPre = prefixEncodedPassword.substring(bcryptStart, bcryptEnd + 1);
        }

        if (EncodingIdConst.MD5_PRE.equals(md5pre)) {
            String md5Password = prefixEncodedPassword.substring(md5End + 1);
            return md5Password;
        } else if (EncodingIdConst.BCRYPT_PRE.equals(bcryptPre)) {
            String bcryptPassword = prefixEncodedPassword.substring(bcryptEnd + 1);
            return bcryptPassword;
        }

        return prefixEncodedPassword;
    }
}
